<script lang="tsx">
import { ElFooter, ElHeader, ElMain } from 'element-plus';
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import { getColClassList, getColStyle } from './utils';
import { useAppStore, useSettingsStore } from '@/store';
import { PropType, defineModel } from 'vue';

interface IAppPageConfig {
  /** 流式布局 */
  isFlow?: boolean;
  /** 显示头部 */
  showFHeader?: boolean;
  /** 全屏 */
  isFullscreen?: boolean;
  /** 固定表格高 */
  isFixed?: boolean;
}

export default defineComponent({
  name: 'AppPage',
  props: {
    config: {
      type: Object as PropType<IAppPageConfig>,
      default: () => ({
        isFlow: false,
        showFHeader: true,
        isFullscreen: false,
        isFixed: true,
      }),
    },
    mainBg: {
      type: String,
      default: '',
    },
    mainPadding: {
      type: String,
      default: '0 0',
    },
    laside: {
      type: Object,
      default: () => ({}),
    },
    raside: {
      type: Object,
      default: () => ({}),
    },
    fheader: {
      type: Object,
      default: () => ({}),
    },
  },
  emits: ['update:config'],
  setup(props, { emit }) {
    const contentHeight = ref(0);
    const collapse = ref(false);

    const appPageRef = ref<HTMLElement | null>(null);
    const contentMainRef = ref<typeof ElMain | null>(null);
    const contentHeaderRef = ref<typeof ElHeader | null>(null);
    const contentFooterRef = ref<typeof ElFooter | null>(null);
    const contentWrapperRef = ref<typeof ElMain | null>(null);

    const computedContentHeight = () => {
      if (contentMainRef.value) {
        const { clientHeight } = contentMainRef.value.$el;
        let headerHeight = 0;
        let footerHeight = 0;
        if (contentHeaderRef.value) {
          headerHeight = parseInt(getComputedStyle(contentHeaderRef.value?.$el)?.height, 10);
        }
        if (contentFooterRef.value) {
          footerHeight = parseInt(getComputedStyle(contentFooterRef.value?.$el)?.height, 10);
        }
        const selfPaddingTop = parseInt(getComputedStyle(contentMainRef.value?.$el)?.paddingTop, 10);
        const selfPaddingBottom = parseInt(getComputedStyle(contentMainRef.value?.$el)?.paddingBottom, 10);
        contentHeight.value = clientHeight - headerHeight - footerHeight - selfPaddingTop - selfPaddingBottom - 1;
      }
    };

    let timer: number | null = null;
    const windowResizeCallBack = () => {
      if (timer) return;
      timer = window.setTimeout(() => {
        timer = null;
        computedContentHeight();
      }, 200);
    };

    const settingsStore = useSettingsStore();
    const appStore = useAppStore();
    const { tagsView } = storeToRefs(settingsStore);
    const { size } = storeToRefs(appStore);
    watch([tagsView, size], windowResizeCallBack, { immediate: true });
    onMounted(() => {
      computedContentHeight();
      window.addEventListener('resize', windowResizeCallBack, false);
    });
    onUnmounted(() => {
      window.removeEventListener('resize', windowResizeCallBack, false);
    });
    onActivated(() => {
      computedContentHeight();
    });

    const appPageConfig = computed({
      get: () => props.config,
      set: (v) => emit('update:config', v),
    });

    // 表格固定高度、区域全屏 与 流式布局 互斥
    watch(
      () => appPageConfig.value.isFlow,
      (v) => v && ((appPageConfig.value.isFixed = false), (appPageConfig.value.isFullscreen = false))
    );
    watch(
      () => [appPageConfig.value.isFixed, appPageConfig.value.isFullscreen],
      ([f, s]) => (f || s) && (appPageConfig.value.isFlow = false)
    );

    const cssVars = computed(() => ({
      '--tags-view-height-calc': settingsStore.tagsViewInNavbar ? '0px' : 'var(--tags-view-height)',
    }));

    return {
      cssVars,
      contentHeight,
      collapse,

      appPageRef,
      contentMainRef,
      contentHeaderRef,
      contentWrapperRef,
      contentFooterRef,
      computedContentHeight,
      windowResizeCallBack,

      appPageConfig,
    };
  },
  render() {
    const renderCollapse = () => {
      const { showCollapse } = this.fheader;
      return (
        <el-button
          v-show={showCollapse}
          type="primary"
          link
          onClick={() => {
            this.collapse = !this.collapse;
            this.windowResizeCallBack();
          }}
        >
          {this.collapse ? '收起' : '展开'}
          <el-icon class="ml-[5px]">{this.collapse ? <ArrowUp /> : <ArrowDown />}</el-icon>
        </el-button>
      );
    };

    const renderFHeader = () => {
      if (!this.appPageConfig.showFHeader) return null;

      const { row = {}, col } = this.fheader;
      const fheaderVNode = this.$slots.fheader?.({ collapse: this.collapse });

      if (fheaderVNode instanceof Array) {
        fheaderVNode.forEach((vNodeItem: any) => {
          const vNodeChildKeys = Object.keys(vNodeItem.children || {});
          if (vNodeItem.type?.name === 'ElForm') {
            vNodeChildKeys.forEach((key) => {
              const _renderFunc = vNodeItem.children[key];

              if (typeof _renderFunc !== 'function') {
                return;
              }

              vNodeItem.children[key] = function renderDef() {
                const children = _renderFunc();
                // 给row的数据
                const rowPropsData = {
                  gutter: 10,
                  ...row,
                };

                const _renderChild = () => {
                  // 这块处理展开按钮
                  {
                    const _getShowCollapseVNode = (vNode: any) => {
                      const childs = vNode.children.default();
                      vNode.children.default = () => {
                        return [...childs, renderCollapse()];
                      };

                      return vNode;
                    };

                    let len = children?.length || 0;
                    while (len > 0) {
                      len -= 1;
                      const lastElFormItemChild = children[len];
                      if (
                        lastElFormItemChild?.type?.componentName === 'ElFormItem' &&
                        // 保证最后一个form-item可被正确渲染
                        typeof lastElFormItemChild?.children?.default === 'function'
                      ) {
                        _getShowCollapseVNode(lastElFormItemChild);
                        break;
                      }
                    }
                  }

                  const colClass = getColClassList(col || { xs: 24, sm: 12, md: 12, lg: 8, xl: 8 }, rowPropsData);
                  const colStyle = getColStyle(rowPropsData);

                  return children.map((vNode: any) => {
                    return vNode?.type?.componentName !== 'ElFormItem' ? (
                      vNode
                    ) : (
                      <div class={['el-col', colClass]} style={colStyle}>
                        {vNode}
                      </div>
                    );
                  });
                };

                return [<el-row {...rowPropsData}>{_renderChild()}</el-row>];
              };
            });
          }
        });
      }

      return (
        <el-header
          class={['page-fixed-header', 'relative', 'pt-15px', 'px-10px', 'rounded-4px', 'mb-5px', 'shadow']}
          v-show={!!fheaderVNode}
        >
          {
            /**
             * 保证vue node节点插入
             */
            fheaderVNode || <div />
          }
        </el-header>
      );
    };

    const renderMainHeader = () => {
      if (!this.$slots.header) return null;
      this.windowResizeCallBack();
      return (
        <el-header class="pb-10px pl-0 pr-0 relative h-auto" ref="contentHeaderRef">
          {this.$slots.header()}
        </el-header>
      );
    };

    const renderMainFooter = () => {
      if (!this.$slots.footer) return null;
      this.windowResizeCallBack();
      return (
        <el-footer class="flex-y-center p-10px overflow-auto" ref="contentFooterRef">
          {this.$slots.footer()}
        </el-footer>
      );
    };

    const renderMain = () => {
      return (
        <el-main
          class="h-100% rounded-4px shadow"
          ref="contentWrapperRef"
          style={{
            backgroundColor: this.mainBg,
            padding: this.mainPadding,
          }}
        >
          {this.$slots.main && (
            <el-main ref="contentMainRef" class="h-100%">
              {renderMainHeader()}

              {this.$slots.main({ height: this.appPageConfig.isFixed ? this.contentHeight || 'auto' : 'auto' })}

              {renderMainFooter()}
            </el-main>
          )}
        </el-main>
      );
    };

    const renderFFooter = () => {
      if (!this.$slots.ffooter) return null;

      return (
        <el-footer class="flex-y-center justify-end p-10px overflow-auto mt-5px rounded-4px">
          {this.$slots.ffooter()}
        </el-footer>
      );
    };

    const renderLAside = () => {
      if (!this.$slots.laside) return null;
      const laside = this.laside || {};
      return (
        <el-aside class={['p-15px', 'overflow-x-hidden', 'rounded-[4px]', 'mr-12px']} {...laside}>
          {this.$slots.laside()}
        </el-aside>
      );
    };
    const renderRAside = () => {
      if (!this.$slots.raside) return null;
      const raside = this.raside || {};
      return (
        <el-aside class={['p-15px', 'overflow-x-hidden', 'bg-white', 'rounded-[4px]', 'ml-12px']} {...raside}>
          {this.$slots.raside()}
        </el-aside>
      );
    };
    return (
      <div
        class={[
          'app-page',
          this.appPageConfig.isFullscreen ? 'app-page__fullscreen' : '',
          this.appPageConfig.isFlow ? 'app-page__flow' : '',
        ]}
        style={this.cssVars}
        ref="appPageRef"
      >
        {this.$slots.default && this.$slots.default()}

        <el-container class={{ 'h-full': !this.$slots.default }}>
          {renderLAside()}
          <el-container class="w-auto" direction="vertical">
            {renderFHeader()}
            {renderMain()}
            {renderFFooter()}
          </el-container>
          {renderRAside()}
        </el-container>
      </div>
    );
  },
});
</script>

<style lang="scss" scoped>
.app-page {
  // 100vh - 导航栏高 - 标签页高（需要判断是否在导航栏内）
  // height: calc(100vh - var(--navbar-height) - var(--tags-view-height-calc));
  height: 100%;
  padding: 5px;
  overflow-x: auto;
  background-color: var(--el-bg-color-page);

  &.app-page__fullscreen {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 2000;
    width: 100%;
    height: 100%;
  }

  &.app-page__flow {
    height: auto;
  }

  .el-header,
  .el-footer,
  .el-main {
    --el-main-padding: 10px;

    background-color: var(--el-bg-color);
  }

  :deep(.el-card__body) {
    height: 100%;
    padding: 0;
  }

  .page-fixed-header {
    height: auto !important;

    :deep(.el-form) {
      width: 100%;
    }

    :deep(.el-form-item) {
      margin-bottom: 15px;

      &.label-hidden {
        .el-form-item__label {
          display: none;
        }

        .el-form-item__content {
          margin-left: 0 !important;
        }
      }
    }
  }
}
</style>
